#!/usr/bin/env.python
# _*_ coding:utf-8 _*_
# # # # # # # # # # # # # # # # # # # #
#  题目:      booktest的视图           #
#  姓名:         李吉辉                #
#  时间:    2018年12月13日21:17:53     #
# # # # # # # # # # # # # # # # # # # #
from django.db import DatabaseError
from rest_framework.filters import OrderingFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import BasePermission, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView, ListAPIView, CreateAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView
from rest_framework import mixins, status
from rest_framework.viewsets import ViewSet, GenericViewSet, ModelViewSet
from rest_framework.decorators import action

from booktest.models import BookInfo
from booktest.serializers import BookInfoSerializer

"""******************************************可选分页器1)PageNumberPagination  2)LimitOffsetPagination*****************************************"""
from rest_framework.pagination import PageNumberPagination

class StandardPageNumberPagination(PageNumberPagination):
    page_size_query_param = 'page_size'
    max_page_size = 10

    # 下面是视图中的
    # 127.0.0.1/books/?page=1&page_size=2
    # pagination_class = StandardPageNumberPagination


from rest_framework.pagination import LimitOffsetPagination

class BookListView(ListAPIView):
    queryset = BookInfo.objects.all().order_by('id')
    serializer_class = BookInfoSerializer
    pagination_class = LimitOffsetPagination

    # 127.0.0.1:8000/books/?offset=3&limit=2
    # offset = 3 & limit = 2 ==> 表示第3条开始 显示2条

"""******************************************分页Pagination局部使用*****************************************"""
class LargeResultsSetPagination(PageNumberPagination):
    # 每页显示数目
    page_size = 3
    # 前端发送的每页数目关键字名，默认为None, 一般设置为page_size,前端不发送每页数目,默认使用自己写的
    page_size_query_param = 'page_size'
    #  前端最多能设置的每页数量(后端限制,固定)
    max_page_size = 3

    # page_query_param 前端发送的页数关键字名，默认为"page"


"""******************************************自定义权限*****************************************"""
class MyPermission(BasePermission):
    def has_object_permission(self, request, view, obj):
        """控制对obj对象的访问权限，此案例决绝所有对对象的访问"""
        return False

"""******************************************视图集之终极集神龙版 ModelViewSet*****************************************"""
# ModelViewSet就是继承 GenericViewSet和Mixin所有的结合体
class BookViewSet(ModelViewSet):
    # 1.指定查询集
    queryset = BookInfo.objects.all()
    # 2.指定序列化器类
    serializer_class = BookInfoSerializer

    # ******* 权限限制 ****** 认证用户         自定义权限
    # permission_classes = [IsAuthenticated, MyPermission]  # 指定访问当前整个类视图时指定的权限

    # filter_backends =   # 指定过滤后端
    # filter_fields = ['btitle', 'bread']   # 指定过滤的字段

    # 指定过滤的后端为排序过滤
    filter_backends = [OrderingFilter]

    # 只有指定的字段才可以进行排序操作
    ordering_fields = ["id", 'bread', 'bcomment']

    # 分页关联绑定那个分页类
    # pagination_class = LargeResultsSetPagination
    # 注意：如果在视图内关闭分页功能，只需在视图内设置
    # pagination_class = None




    # 装饰器第一个参数是 请求方式
    @action(["get"], detail=False)   # detail它是来控制router生成路由时,需不需要加pk
    def latest(self, request):
        # get: latest
        """
            获取倒序后的最新书籍数据
        """

        # 异常处理 Exceptions 测试, 自子抛出错误
        raise DatabaseError()

        # latest是先把id反转,然后在取第一个
        book = BookInfo.objects.latest('id')
        serializer = BookInfoSerializer(book)
        return Response(serializer.data)

    @action(methods=["put"], detail=True)
    def update_bread(self, request, pk):
        """修改书籍阅读量"""
        # put: update_bread
        book = self.get_object()
        book.bread = request.data.get('bread')
        book.save()

        serializer = BookInfoSerializer(book)
        return Response(serializer.data)


"""******************************************视图集之GenericViewSet和mixins*****************************************"""
# class BookViewSet(mixins.ListModelMixin, GenericViewSet):
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer


"""******************************************视图集之ViewSet(视图集和视图区别: 主要是一个了类可以写全部和路由写法不同)*****************************************"""
# class BookViewSet(ViewSet):
#     """继承视图集祖宗版(干净版)ViewSet"""
#
#     def list(self, request):
#         """获取所有图书"""
#
#         # 1.获取所有数据
#         qs = BookInfo.objects.all()
#         # 2.创建序列化器对象  --> 因为要得到多个,所以要many=True
#         serializer = BookInfoSerializer(qs, many=True)
#         # 3.响应  [通过data属性可以获取序列化后的数据]
#         return Response(serializer.data)
#
#     def retrieve(self, request, pk):
#         """获取单一图书"""
#         try:
#             # 1.获取对应单个的模型对象
#             book = BookInfo.objects.get(id=pk)
#         except BookInfo.DoesNotExist:
#             # 获取异常响应异常状态码
#             return Response(status=status.HTTP_400_BAD_REQUEST)
#         # 2.创建序列化器对象
#         serializer = BookInfoSerializer(book)
#         # 3.响应  [通过data属性可以获取序列化后的数据]
#         return Response(serializer.data)

"""******************************************Mixin升级版的子类们(功能更加强大)*****************************************"""

# class BookListView(ListAPIView, CreateAPIView):
#     """继承Mixin升级版的子类ListAPIView/CreateAPIView来实现查询所有图书信息和新增图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer
#
#
#
# class BookDetailView(RetrieveAPIView, DestroyAPIView, UpdateAPIView):
#     """继承Mixin升级版的子类CreateAPIView, DestroyAPIView, UpdateAPIView来实现查询单一查询/删除/更新图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer



"""******************************************GenericAPIView和Mixin结合*****************************************"""
# class BookListView(mixins.ListModelMixin, GenericAPIView):
#     """继承GenericAPIView和mixins.ListModelMixin来实现查询所有图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer
#
#     def get(self, request):
#         """获取所有图书接口"""
#         # 响应数据
#         return self.list(request)
#
#
# class BookDetailView(mixins.CreateModelMixin, GenericAPIView):
#     """继承GenericAPIView和mixins.CreateModelMixin来实现查询单一查询图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer
#
#     # 注意点: pk只需要占位,不需要调用,因为GenericAPIView内部实现了pk获取调用
#     def get(self, request, pk):
#         """获取单一图书接口"""
#         # 响应数据
#         return self.create(request)



"""******************************************GenericAPIView*****************************************"""
# class BookListView(GenericAPIView):
#     """继承GenericAPIView来实现查询所有图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer
#
#     def get(self, request):
#         """获取所有图书接口"""
#         # 获取查询集
#         qs = self.get_queryset()
#         # 获取序列化器对象
#         serializer = self.get_serializer(qs, many=True)
#
#         # 响应数据
#         return Response(serializer.data)
#
#
# class BookDetailView(GenericAPIView):
#     """继承GenericAPIView来实现查询单一查询图书信息"""
#
#     # 1.指定查询集
#     queryset = BookInfo.objects.all()
#     # 2.指定序列化器类
#     serializer_class = BookInfoSerializer
#
#     # 注意点: pk只需要占位,不需要调用,因为GenericAPIView内部实现了pk获取调用
#     def get(self, request, pk):
#         """获取单一图书接口"""
#         # 获取要查询的单个模型对象
#         book = self.get_object()  # 查询单一特殊获取  get_object()
#         # 获取序列化器对象
#         serializer = self.get_serializer(book)
#
#         # 响应数据
#         return Response(serializer.data)

"""******************************************APIView*****************************************"""
"""下面这个是用APIView实现的获取列表视图"""
# class BooksAPiView(APIView):
#     """获取所有图书数据"""
#
#
#     def get(self, request):
#         """
#         获取所有图片接口
#         :param request: 此请求对象是Request
#         :return: Response类对象
#         """
#         # 1.获取所有数据
#         qs = BookInfo.objects.all()
#         # 2.创建序列化器对象  --> 因为要得到多个,所以要many=True
#         serializer = BookInfoSerializer(qs, many=True)
#         # 3.响应  [通过data属性可以获取序列化后的数据]
#         return Response(serializer.data)